<?php

namespace App\GameChannel;

use App\Datalog\ErrorLog;
use App\Jobs\PayGameCbQueue;
use App\Models\Channels;
use App\Models\GameChannel;
use App\Models\Log\LogCbgame;
use App\Models\Orders;
use App\Services\GameChannelService;
use App\Services\GameService;
use App\Services\SdkService;
use Illuminate\Support\Facades\Http;

class PayGameCallback
{
    protected $tradeNo;

    public function __construct($trade_no)
    {
        $this->tradeNo = $trade_no;
    }

    // 更新状态
    private function setStatus($order, $status)
    {
        $order->cb_num       = $order->cb_num + 1;
        $order->last_cb_time = time();
        $order->status       = $status;
        $order->save();

        // 如果发货失败，则每隔1分钟重新通知一遍，进行5次，如果超过次数取消通知，待人工补单
        if ($status == Orders::PAY_STATUS_CALLBACK_ERR && $order->cb_num < 5) {
            PayGameCbQueue::dispatch($this->tradeNo, $status)->onQueue('high')->delay(60);
        }
    }

    // 给予支付成功的订单发货
    public function cbGameByPayOk()
    {
        return $this->cbGame(Orders::PAY_STATUS_PAY_OK);
    }

    // 给予发货失败的订单重新发货
    public function cbGameByCbErr()
    {
        return $this->cbGame(Orders::PAY_STATUS_CALLBACK_ERR);
    }

    // 人工补单
    public function cbGameByBudan()
    {
        return $this->cbGame();
    }

    // 通知游戏服发货
    public function cbGame($check_status = null)
    {
        $order = Orders::where('trade_no', $this->tradeNo)->first();
        if (!$order) {
            return false;
        }

        // 订单状态不对
        if ($check_status && $order->status !== $check_status) {
            return false;
        }

        // 根据游戏id获取游戏数据
        $game = GameService::getInstance()->get($order->game_id);
        if (!$game) {
            return false;
        }

        $game_channel = GameChannelService::getInstance()->get($order->game_channel_id, true);
        if (!$game_channel) {
            return false;
        }

        // 组织待通知发货参数
        $channel_trade_no = $order->channel_trade_no;
        if (empty($channel_trade_no)) {
            $channel_trade_no = $order->trade_no;
        }

        $amount = $order->amount;

        // 部分游戏写死0.1折通知
        if (in_array($order->game_id, []) && $order->channel == 17) {
            $amount = $order->amount * 0.01;
        }

        $params = [
            'trade_no'         => $order->trade_no,
            'game_trade_no'    => $order->game_trade_no,
            'channel_trade_no' => $channel_trade_no,
            'amount'           => $amount,
            'user_id'          => $order->user_id,
            'game_id'          => $order->game_id,
            'channel'          => $order->channel,
            'channel_openid'   => $order->channel_openid,
            'goods_id'         => $order->goods_id,
            'goods_name'       => $order->goods_name,
            'server_id'        => $order->server_id,
            'server_name'      => $order->server_name,
            'role_id'          => $order->role_id,
            'payok_time'       => $order->payok_time,
            'time'             => time(),
        ];

        if ($order->channel == Channels::CHANNEL_LINGCHUANG) {
            $params['payFrom'] = $order->extend_1;
        }

        // 签名
        $params['sign'] = SdkService::getInstance()->createCpPaySign($game['appsecret'], $params);

        $url = $game['callback_url'];
        if (!empty($game_channel['callback_url'])) {
            $url = $game_channel['callback_url'];
        }

        if (strpos($url, '?') > 1) {
            $url = $url . "&" . http_build_query($params);
        } else {
            $url = $url . "?" . http_build_query($params);
        }

        $now = time();
        $ret = '';
        try {
            $response = Http::timeout(10)->get($url);
            if ($response->ok()) {
                $ret = $response->body();
            }
        } catch (\Throwable $exception) {
            // ErrorLog::getInstance()->addThrowable($exception);
            $ret = 'timeout';
        }

        if (strlen($ret) > 120) {
            $ret = substr($ret, 0, 120);
        }

        // 先保存日志
        $log                = new LogCbgame;
        $log->create_time   = $now;
        $log->trade_no      = $order->trade_no;
        $log->game_trade_no = $order->game_trade_no;
        $log->game_id       = $order->game_id;
        $log->url           = $url;
        $log->ret           = $ret;
        $log->save();

        if (!$ret || $ret !== 'SUCCESS') {
            $this->setStatus($order, Orders::PAY_STATUS_CALLBACK_ERR);
            return false;
        } else {
            $order->cbok_time = time();
            $this->setStatus($order, Orders::PAY_STATUS_CALLBACK_OK);
            return true;
        }
    }
}
